﻿/*======================================*\
* Author: Vincent
* LastModifyUser: Vincent
* Description:  
* CreateTime： 2012-05
* Remark:  
\*======================================*/

using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;
using System.Globalization;
using ZLDC.GenericFrame.Support;

namespace AppCode.Domain.Services
{
    /// <summary>
    /// 数据集对象转换
    /// </summary>
    public class EntityMapper
    {
        /// <summary>
        /// 属性信息静态字典
        /// </summary>
        private static IDictionary<Type, PropertyInfo[]> propertyInfoCache = new Dictionary<Type, PropertyInfo[]>();

        /// <summary>
        /// 返回对象属性信息
        /// </summary>
        /// <param name="objType"></param>
        /// <returns></returns>
        private static PropertyInfo[] GetObjProperties(Type objType)
        {
            if (propertyInfoCache.ContainsKey(objType))
            {
                return propertyInfoCache[objType];
            }
            PropertyInfo[] tempProperties = objType.GetProperties();
            if (tempProperties != null)
                propertyInfoCache.Add(objType, tempProperties);
            return tempProperties;
        }

        /// <summary>
        /// 单个对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="adaptedRow"></param>
        /// <returns></returns>
        public static T ToEntity<T>(DataRow adaptedRow) where T : IEntity, new()
        {
            T item = new T();
            if (adaptedRow == null)
            {
                return item;
            }

            item = Activator.CreateInstance<T>();
            Type objType = item.GetType();
            CopyToEntity(item, objType, adaptedRow);

            return item;
        }

        /// <summary>
        /// 返回一组对象成员
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dt"></param>
        /// <returns></returns>
        public static List<T> ToEntity<T>(DataTable dt) where T : IEntity, new()
        {
            List<T> items = new List<T>();
            T item = new T();
            if (dt == null)
            {
                return items;
            }
            item = Activator.CreateInstance<T>();
            var dtRows = dt.Rows;
            Type objType = item.GetType();
            for (int i = 0; i < dt.Rows.Count; i++)
            {
                item = new T();
                CopyToEntity(item, objType, dtRows[i]);
                items.Add(item);
            }

            return items;
        }


        /// <summary>
        /// 值复制,重载
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="objType"></param>
        /// <param name="adaptedRow"></param>
        public static void CopyToEntity(object entity, Type objType, DataRow adaptedRow)
        {
            if (entity == null || adaptedRow == null)
            {
                return;
            }
            PropertyInfo[] propertyInfos = GetObjProperties(objType);

            foreach (PropertyInfo propertyInfo in propertyInfos)
            {
                if (!CanSetPropertyValue(propertyInfo, adaptedRow))  //判断属性是否可写及datarow中是否存在相应的属性字段
                {
                    continue;
                }

                try
                {
                    if (adaptedRow[propertyInfo.Name] is DBNull)
                    {
                        propertyInfo.SetValue(entity, null, null);
                        continue;
                    }
                    SetPropertyValue(entity, adaptedRow, propertyInfo);
                }
                finally
                {

                }
            }
        }


        public static void CopyToEntity(object entity, DataRow adaptedRow)
        {
            if (entity == null || adaptedRow == null)
            {
                return;
            }
            PropertyInfo[] propertyInfos = entity.GetType().GetProperties();

            foreach (PropertyInfo propertyInfo in propertyInfos)
            {
                if (!CanSetPropertyValue(propertyInfo, adaptedRow))
                {
                    continue;
                }

                try
                {
                    if (adaptedRow[propertyInfo.Name] is DBNull)
                    {
                        propertyInfo.SetValue(entity, null, null);
                        continue;
                    }
                    SetPropertyValue(entity, adaptedRow, propertyInfo);
                }
                finally
                {

                }
            }
        }

        /// <summary>
        /// 判断某属性是否可写并检查数据集中是否存在相应的属性值
        /// </summary>
        /// <param name="propertyInfo"></param>
        /// <param name="adaptedRow"></param>
        /// <returns></returns>
        private static bool CanSetPropertyValue(PropertyInfo propertyInfo, DataRow adaptedRow)
        {
            if (!propertyInfo.CanWrite)
            {
                return false;
            }

            if (!adaptedRow.Table.Columns.Contains(propertyInfo.Name))
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// 反射设置对象属性值
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="adaptedRow"></param>
        /// <param name="propertyInfo"></param>
        private static void SetPropertyValue(object entity, DataRow adaptedRow, PropertyInfo propertyInfo)
        {
            if (propertyInfo.PropertyType == typeof(DateTime?) ||
                propertyInfo.PropertyType == typeof(DateTime))
            {
                DateTime date = DateTime.MaxValue;
                DateTime.TryParse(adaptedRow[propertyInfo.Name].ToString(),
                    CultureInfo.CurrentCulture, DateTimeStyles.None, out date);

                propertyInfo.SetValue(entity, date, null);
            }
            else
            {
                propertyInfo.SetValue(entity, adaptedRow[propertyInfo.Name], null);
            }
        }
    }
}
